--- title: "02-super深层剖析" created: 2025-12-02 tags: - Java --- # super深层剖析 ### **一、设计原理:继承链的初始化规则** Java 子类对象的本质是「父类对象的扩展」,因此**父类初始化必须先于子类**。 - **编译器隐式插入** `super()`: 若子类构造函数未显式调用 `super()` 或 `this()`,编译器会自动添加 `super()`(调用父类无参构造)。 ```java public class Child extends Parent { // 编译后隐式添加 super(); public Child() {} } ``` - **构造函数调用的强制性**: 若父类**没有无参构造函数**(如只有有参构造),子类必须显式调用 `super(参数)`,否则编译失败。 java ```java class Parent { public Parent(int value) {} // 无默认构造函数 } class Child extends Parent { public Child() { // super(10); 必须显式调用,否则报错 } } ``` **原理**:Java 对象模型要求继承链上所有父类的构造函数必须被调用,确保对象状态完整。 ### **二、**`super` **vs** `this`**:内存视角的本质区别** | **维度** | `super` | `this` | | --- | --- | --- | | **本质** | 指向**父类对象**的引用(逻辑概念) | 指向**当前对象**的引用(实际内存地址) | | **作用域** | 用于跨类(子类→父类)访问 | 用于同类内访问 | | **构造函数** | 调用父类构造函数 | 调用本类其他构造函数 | | **成员访问** | 访问父类被覆盖的成员 | 访问本类成员(包括隐藏的同名成员) | **关键对比示例**: ```java class Parent { protected int value = 10; public Parent(int v) { value = v; } } class Child extends Parent { private int value = 20; public Child(int v) { super(v); // 调用父类构造,初始化父类value this.value = v * 2; // 初始化子类value } public void print() { System.out.println("父类值:" + super.value); // 输出父类被覆盖的value System.out.println("子类值:" + this.value); // 输出子类value } } ``` ### **三、编译期与运行期的行为差异** 1. **编译期绑定**: - `super.方法名()` 调用父类方法时,编译器会检查父类是否存在该方法,但**运行时动态绑定**(根据对象实际类型调用)。 ```java Parent p = new Child(); p.method(); // 若Child重写method,实际调用子类实现(多态) ``` 2. **权限校验**: - `super` 访问父类成员时,需遵守访问权限规则(如父类字段为 `private` 时,`super.字段` 编译报错)。 ### **四、常见问题的深度解答** #### **Q1:super () 和 this () 能否同时出现在构造函数中?** **答**:不能。 - 二者都必须作为构造函数的**第一行代码**,且作用冲突(`super()` 初始化父类,`this()` 调用本类其他构造),因此只能二选一。 - **示例错误**: ``` public Child() { super(); // 第一行 this(10); // 报错:Constructor call must be the first statement in a constructor } ``` #### **Q2:子类构造器为何必须调用父类构造器?默认调用的是哪个?** **答**: - **原因**:子类继承父类的状态(字段、方法),需先完成父类初始化,确保继承的状态合法。 - **默认行为**:若父类有**无参构造函数**,子类隐式调用 `super()`;若父类无无参构造,则必须显式调用 `super(参数)`。 #### **Q3:如何在子类中访问父类被重写的方法?** **答**: 使用 `super.方法名()` 强制调用父类实现,例如: ```java @Override public void method() { super.method(); // 调用父类被重写的method // 子类扩展逻辑 } ``` ### **五、容易忽略的使用场景** 1. **父类私有方法的访问限制**: 若父类方法为 `private`,子类无法通过 `super` 调用(私有成员对子类不可见)。 2. **接口的默认方法与** `super`: Java 8+ 接口支持默认方法,子类实现多个接口时,可通过 `接口名.super.方法()` 调用指定接口的默认实现(类似多重继承的语法糖)。 ```java interface A { default void func() { System.out.println("A"); } } interface B { default void func() { System.out.println("B"); } } class C implements A, B { @Override public void func() { A.super.func(); // 显式调用接口A的默认方法 B.super.func(); // 显式调用接口B的默认方法 } } ``` ### **总结:super 的「三重角色」** 1. **初始化协调者**:确保父类构造优先执行,维护继承链的状态一致性。 2. **成员访问仲裁者**:在子类覆盖父类成员时,提供「逆向访问」的能力。 3. **多态机制的补充者**:配合 `@Override` 实现「复用父类逻辑 + 扩展子类特性」的设计模式。 理解 `super` 不仅是语法规则,更是 Java 继承体系中「责任链」和「层次化构建」思想的体现,这在设计复杂类层次结构时尤为重要。 --- ⬅️ [[01-super关键字|super 关键字]] 🏠 [[00-Java|00-Java]] ➡️ [[01-java中的位运算技巧|java中的位运算技巧]]